/*
 * arena.cpp
 *
 *  Created on: Nov 20, 2013
 *      Author: killerg
 */

#include "../server_deps.h"
#include "../server.h"
#include "../server_cfg.h"
#include "../server_console.h"

#include "arena.h"
#include "proto_mgr.h"
#include "mail_mgr.h"
#include "game_cfg.h"

#include "share/db_mgr.h"
#include "share/clock.h"




bool arena_t::init() {
    bool ret = true;
    ret = ret && init_rank();
    ret = ret && init_rewarding();

    _inited = ret;

    return ret;
}

bool arena_t::init_rewarding() {
    bool ret = g_dbf->get(
            fmt_cstr("_arena_rewarding:%d", g_cfg->ServerId),
            [&ret, this](db_error_t err, const Json::Value &value){
                switch (err) {
                case DBE_Success: {
                    _rewarding = value.get("rewarding", false).asBool();
                    _next_index = value.get("next_index", -1).asInt();
                    ret = true;
                    break;
                }
                case DBE_NoExist:
                    UTIL_LOG(I, "no _arena_rewarding data");
                    ret = true;
                    break;
                default:
                    UTIL_LOG(E,
                            "load _arena_rewarding data err: %s",
                            db_strerror(err));
                    ret = false;
                    break;
                }
            });
    if (!ret) {
        UTIL_LOG(E, "arena_t::init get _arena from db failed");
        return false;
    }

    g_dbf->wait();

    return ret;
}

void arena_t::save_rewarding() {
	if (!g_dbf->ok())
		return;

    Json::Value json;
    json["objtype"] = "arena_rewarding";
    json["serverid"] = g_cfg->ServerId;
    json["rewarding"] = _rewarding;
    json["next_index"] = _next_index;
    g_dbf->set(
            fmt_cstr("_arena_rewarding:%d", g_cfg->ServerId),
            json,
            [](db_error_t err){
                switch (err) {
                case DBE_Success:
                    break;
                default:
                    UTIL_LOG(E, "err save arena_rewarding %s", db_strerror(err));
                    break;
                }
            });
}

bool arena_t::init_rank() {
    memset(array, -1, sizeof(array));
    players.clear();

    bool ret = g_dbf->get(
            fmt_cstr("_arena_rank:%d", g_cfg->ServerId),
            [&ret, this](db_error_t err, const Json::Value &value){
                switch (err) {
                case DBE_Success: {
                    const Json::Value &json_arr = value["rank"];
                    for (auto itr = json_arr.begin(); itr != json_arr.end(); ++itr)
                        first_insert((*itr).asInt64());

                    ret = true;
                    break;
                }
                case DBE_NoExist:
                    UTIL_LOG(I, "no _arena_rank data");
                    ret = true;
                    break;
                default:
                    UTIL_LOG(E,
                            "load _arena_rank data err: %s",
                            db_strerror(err));
                    ret = false;
                    break;
                }
            });
    if (!ret) {
        UTIL_LOG(E, "arena_t::init get _arena from db failed");
        return false;
    }

    g_dbf->wait();

    return ret;
}
void arena_t::save_rank() {
	if (!g_dbf->ok())
		return;

    Json::Value json;
    json["objtype"] = "arena_rank";
    json["serverid"] = g_cfg->ServerId;
    Json::Value &json_arr = json["rank"];
    for (int i=0; i<players.size(); ++i)
        json_arr.append(Json::Int64(array[i]));
    bool res = g_dbf->set(
            fmt_cstr("_arena_rank:%d", g_cfg->ServerId),
            json,
            [](db_error_t err){
                switch (err) {
                case DBE_Success:
                    break;
                default:
                    UTIL_LOG(E, "err save arena_rank %s", db_strerror(err));
                    break;
                }
            });
    if (res) {
        _chged = false;
    }

}
void arena_t::destroy() {
    if (_inited) {
        save_rank();
        save_rewarding();
        g_dbf->wait();
    }
    players.clear();
    memset(array, -1, sizeof(array));
}

int32_t get_rewardid(int index) {
    std::vector<tagProtoArenaReward> &vec = g_svr.protomgr->_arrProtoArenaReward;
    for (auto itr = vec.begin(); itr != vec.end(); ++itr) {
        if (index >= itr->min && index <= itr->max)
            return itr->rewardid;
    }

    return -1;
}

void arena_t::update() {
    if (g_game_cfg->ArenaRankRewardMinute == g_clock->tm_now.tm_min
        && g_game_cfg->ArenaRankRewardHour == g_clock->tm_now.tm_hour
        && g_clock->min_jump) {
        if (!_rewarding)
            set_rewarding(true);
    }

    if (_rewarding) {
        if (_next_index >= 0 && _next_index < players.size()) {
            int64_t playerid = array[_next_index];
            int rank = _next_index+1;

            int32_t rewardid = -1;
            for (auto &itr : g_protomgr->_arrProtoArenaReward) {
                if (rank >= itr.min && rank <= itr.max) {
                    rewardid = itr.rewardid;
                    break;
                }
            }

            if (rewardid >= 0) {
                g_mail->send_system(
                        playerid,
                        EMT_ArenaRankReward,
                        fmt_cstr("%d", rank),
                        rewardid);
            }

            _next_index++;
            if (_next_index >= players.size()) {
                _next_index = -1;
                _rewarding = false;
            }
        } else {
            _next_index = -1;
            _rewarding = false;
        }
        save_rewarding();

    } else {
        static double save_timer = 30.0f;
        save_timer -= g_clock->delta;

        if (_chged && save_timer <= 0.0f) {
            save_timer = 30.0f;
            save_rank();
        }
    }
}

int arena_t::get_index(int64_t playerid) {
    if (!has_player(playerid))
        return -1;

    for (int i=players.size()-1; i>=0; --i)
        if (array[i] == playerid)
            return i;

    return -1;
}

bool arena_t::is_before(int64_t playerid, int64_t before) {
    if (!has_player(before))
        return false;

    if (has_player(before) && !has_player(playerid))
        return true;

    int heidx = -1;
    int myidx = -1;
    for (int i=players.size()-1; i>=0; --i) {
        if (playerid == array[i])
            myidx = i;
        if (before == array[i])
            heidx = i;

        if (heidx >= 0 && myidx < 0)
            return false;
    }

    return true;
}

// before一定在榜单中
// playerid不一定在榜单中
int arena_t::insert(int64_t playerid, int64_t before) {
    assert(before>=0);
    assert(has_player(before));

    // 找到before的index
    // 找到我的index
    int myidx = -1;
    int heidx = -1;
    for (int i=players.size()-1; i>=0; --i) {
        assert(array[i] >= 0);
        if (array[i] == before)
            heidx = i;
        if (array[i] == playerid)
            myidx = i;

        if (heidx >= 0) {
            if (myidx >= 0)
                break;
        }
    }

    // 若不在榜单中
    if (myidx < 0) {
        // 满了，删除最后的
        if (is_full()) {
            players.erase(array[RANK_SIZE-1]);
            array[RANK_SIZE-1] = -1;
        }
        // 把我放到最后

        myidx = players.size();
        array[myidx] = playerid;
        players.insert(playerid);
    } else {
        assert(myidx > heidx);
    }

    // 把从before的index的id到myindex串
    for (int i=myidx; i>heidx; --i)
        array[i] = array[i-1];

    array[heidx] = playerid;
    _chged = true;
    return heidx;
}

// 榜单未满，直接加进去
// return 排名
int arena_t::first_insert(int64_t playerid) {
    assert(!has_player(playerid));
    assert(!is_full());

    int idx = players.size();
    array[idx] = playerid;
    players.insert(playerid);

    _chged = true;
    return idx;
}

// 查询名词和前面的玩家 return 排名
int arena_t::query(int64_t myid, list<int64_t> &lst, int interval) {
    lst.clear();
    interval = max(1, interval);

    if (!has_player(myid)) {
        assert(is_full() || rewarding());
        for (int i=RANK_SIZE-1; i>=0; i-=interval) {
            lst.push_back(array[i]);
            if (lst.size() >= OPPO_SIZE)
                break;
        }
        return -1;
    } else {
        // 找我自己
        int myidx = -1;
        for (int i=players.size()-1; i>=0; --i) {
            if (array[i] == myid) {
                myidx = i;
                break;
            }
        }
        assert(myidx >= 0);
        for (int i=myidx-1; i>=0; i-=interval) {
            lst.push_back(array[i]);
            if (lst.size() >= OPPO_SIZE)
                break;
        }
        return myidx;
    }
}
